/**
 * @author SongBin on 2021/4/26.
 */
package com.etone.smartAudit.controller;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.etone.smartAudit.annotation.LoginAdmin;
import com.etone.smartAudit.domain.Admin;
import com.etone.smartAudit.domain.ProjectFile;
import com.etone.smartAudit.error.CustomParameterizedException;
import com.etone.smartAudit.mapper.AdminMapper;
import com.etone.smartAudit.onlyoffice.entity.OnlyOfficeConfig;
import com.etone.smartAudit.onlyoffice.entity.OnlyofficeFileModel;
import com.etone.smartAudit.onlyoffice.entity.UserBean;
import com.etone.smartAudit.onlyoffice.entity.dto.OnlyofficeDTO;
import com.etone.smartAudit.onlyoffice.entity.vo.FileModeVo;
import com.etone.smartAudit.onlyoffice.result.RestResult;
import com.etone.smartAudit.onlyoffice.util.PathUtil;
import com.etone.smartAudit.security.SecurityUtils;
import com.etone.smartAudit.service.OfficeFileService;
import com.etone.smartAudit.service.ProjectFileService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import springfox.documentation.annotations.ApiIgnore;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.Scanner;

@Api(value = "onlyoffice文件接口", tags = "onlyoffice文件接口")
@Slf4j
@RestController
public class OnlyOfficeController {


    @Autowired
    private OnlyOfficeConfig officeConfig;


    @Autowired
    private ProjectFileService fileService;

    @Autowired
    private AdminMapper adminMapper;

    @Value("${audit.filePath}")
    private String homePath;

    @Autowired
    private OfficeFileService officeFileService;

    @Value("${only_office.api_host:''}")
    private String apiHost;
    @Value("${only_office.go_back:''}")
    private String goBackUrl;

    // 查看报告接口
    @ApiOperation(value = "查看报告接口", tags = "jiayen")
    @GetMapping(value = "/onlyoffice/viewOffice/{fId}")
    public FileModeVo showReportForOnlyofficeApi(HttpServletRequest request, @ApiParam("文件id") @PathVariable Integer fId) {
        FileModeVo result = new FileModeVo();
        OnlyofficeDTO onlyofficeDTO = getOnlyofficeDto(fId);
        OnlyOfficeConfig fConfig = officeConfig.init();
        String token = getTtoken();
        try {
            UserBean loginUser = getUserBean();
            String fileName = onlyofficeDTO.getFileName();
            String baseUrl = getBaseUrl(request);

            //设置文件类型与地址
            onlyofficeDTO.setType("show");
            onlyofficeDTO.setFileUrl(String.format("%s/projectFile/download/%s", baseUrl, fId));
            onlyofficeDTO.setGobackUrl(goBackUrl);
            OnlyofficeFileModel file = new OnlyofficeFileModel(loginUser, onlyofficeDTO, "view");
            String query = "?type=show&token=" + token;
            file.editorConfig.callbackUrl = baseUrl + "/onlyoffice/callback" + query;
            result.setConfig(file);
            result.setFileName(fileName);
            result.setJsApiUrl(fConfig.getApiJs());

        } catch (Exception e) {
            log.error(e.getMessage());
            throw new CustomParameterizedException(e.getMessage());
        }
        return result;
    }


    @ApiOperation(value = "编辑文档接口", tags = "jiayen")
    @GetMapping(value = "/onlyoffice/editOffice/{fId}")
    public FileModeVo editReportForOnlyofficeApi(HttpServletRequest request, @ApiIgnore @LoginAdmin Admin admin, @ApiParam("文件id") @PathVariable Integer fId) {
        FileModeVo vo = new FileModeVo();
        OnlyofficeDTO onlyofficeDTO = getOnlyofficeDto(fId);
        OnlyOfficeConfig fConfig = officeConfig.init();
        try {
            UserBean loginUser = getUserBean();
            String fileId = onlyofficeDTO.getFileId();
            String fileName = onlyofficeDTO.getFileName();
            String baseUrl = getBaseUrl(request);

            //设置文件类型与地址
            onlyofficeDTO.setType("edit");
            onlyofficeDTO.setFileUrl(String.format("%s/projectFile/download/%s", baseUrl, fId));

            //锁定文件编辑状态
            officeFileService.writeEditStatus(fId);
            officeFileService.saveHistoryVersion(admin, fileService.getById(fileId));
            onlyofficeDTO.setGobackUrl(goBackUrl);
            OnlyofficeFileModel file = new OnlyofficeFileModel(loginUser, onlyofficeDTO, "edit");
            String query = "?type=edit&fileId=" + fileId + "&token=" + getTtoken() + "&filePath=" + URLEncoder.encode(onlyofficeDTO.getFilePath(), "utf-8");
            file.editorConfig.callbackUrl = baseUrl + "/onlyoffice/callback" + query;
            vo.setConfig(file);
            vo.setJsApiUrl(fConfig.getApiJs());
            vo.setFileName(fileName);
        } catch (Exception e) {
            log.error(e.getMessage());
            throw new CustomParameterizedException("服务器异常");
        }
        return vo;
    }

    @PostMapping(value = "/onlyoffice/callback")
    @ApiOperation(value = "文档回调接口", tags = "jiayen")
    public void IndexServlet(HttpServletResponse response, HttpServletRequest request) throws IOException {
        RestResult<Object> result = new RestResult<>();
        officeConfig.init();
//        UserBean loginUser = getUserBean();
        PrintWriter writer = null;
        JSONObject jsonObj = null;
        log.debug("===save edited file------------");
        String filePath = URLDecoder.decode(request.getParameter("filePath"), "utf-8");
        try {
            writer = response.getWriter();
            Scanner scanner = new Scanner(request.getInputStream()).useDelimiter("\\A");
            String body = scanner.hasNext() ? scanner.next() : "";
            jsonObj = JSON.parseObject(body);
            log.debug("===saveeditedfile:" + jsonObj.get("status"));
            String status = jsonObj != null ? jsonObj.get("status").toString() : "";
            if ("6".equals(status)) {//新建报告不强制手动操作时状态为2
                String type = request.getParameter("type");
                String downloadUri = (String) jsonObj.get("url");
                if (StrUtil.isNotEmpty(downloadUri) && downloadUri.contains("183.6.26.102")) {
                    downloadUri = downloadUri.replace("183.6.26.102", "192.168.8.92");
                }
                if ("track".equals(type)) {
                    log.debug("====文档编辑完成，现在开始保存编辑后的文档，其下载地址为:" + downloadUri);
                    String fileUrl = request.getParameter("fileUrl");
                    URL url = new URL(downloadUri);
                    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                    InputStream stream = connection.getInputStream();
                    String oldFilePath = filePath;
                    File oldFile = new File(oldFilePath);
                    try (FileOutputStream out = new FileOutputStream(oldFile)) {
                        int read;
                        final byte[] bytes = new byte[1024];
                        while ((read = stream.read(bytes)) != -1) {
                            out.write(bytes, 0, read);
                        }
                        out.flush();
                    }
                    connection.disconnect();

                } else if ("show".equals(type)) {//查看报告
                    log.debug("====只查看不保存:");
                } else if ("edit".equals(type)) {//修改报告
                    log.debug("====文档编辑完成，现在开始保存编辑后的文档，其下载地址为:" + downloadUri);
                    URL url = new URL(downloadUri);
                    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                    InputStream stream = connection.getInputStream();
                    String oldFilePath = filePath;
                    File oldFile = new File(oldFilePath);
                    try (FileOutputStream out = new FileOutputStream(oldFile)) {
                        int read;
                        final byte[] bytes = new byte[1024];
                        while ((read = stream.read(bytes)) != -1) {
                            out.write(bytes, 0, read);
                        }
                        out.flush();
                        log.debug("============保存中============");
                    }
                    connection.disconnect();

                    //锁定文件编辑状态
                    Integer fileId = Integer.valueOf(request.getParameter("fileId"));
                    officeFileService.writeEditStatus(fileId);
                }
            } else if ("4".equals(status)) {
                log.info("本次编辑结束");
                //更新key
                Integer fileId = Integer.valueOf(request.getParameter("fileId"));
                ProjectFile file = fileService.getById(fileId);
                file.setOfficeKey(IdUtil.fastSimpleUUID());
                fileService.updateById(file);

                //解除文件编辑状态
                officeFileService.removeEditStatus(fileId);
            } else if ("2".equals(status)) {
                log.info("文档准备好保存");
                //更新key
                Integer fileId = Integer.valueOf(request.getParameter("fileId"));
                ProjectFile file = fileService.getById(fileId);
                file.setOfficeKey(IdUtil.fastSimpleUUID());

                //修改文件大小
                File oldFile = new File(filePath);
                file.setSize(oldFile.length());
                fileService.updateById(file);

                //解除文件编辑状态
                officeFileService.removeEditStatus(fileId);

            }
        } catch (Exception e) {
            log.error(e.getMessage());
            log.debug("保存失败:", e);
        }
        String status = jsonObj != null ? jsonObj.get("status").toString() : "";
        if ("3".equals(status) || "7".equals(status)) {//不强制手动保存时为6,"6".equals(status)
            log.debug("====保存失败:");
            writer.write("{\"error\":0}");
        } else {
            log.debug("状态为：0");
            writer.write("{\"error\":" + "0" + "}");
        }
    }

    /***
     * 获取用户信息
     * @return
     */
    private UserBean getUserBean() {
        // 获取当前登录用户
        String loginAdminName = SecurityUtils.getCurrentUserLogin();
        Admin admin = adminMapper.findByAccount(loginAdminName);
        UserBean userBean = new UserBean();
        if (admin != null) {
            userBean.setUserId(admin.getId());
            userBean.setUsername(admin.getNickName());
        }
        return userBean;
    }

    /**
     * 获取文件信息
     *
     * @param fId
     * @return
     */
    private OnlyofficeDTO getOnlyofficeDto(Integer fId) {
        //获取文件信息
        ProjectFile file = fileService.getById(fId);
        if (file == null) {
            throw new CustomParameterizedException("当前文件不存在");
        }
        if (StrUtil.isEmpty(file.getOfficeKey())) {
            file.setOfficeKey(IdUtil.fastSimpleUUID());
            fileService.updateById(file);
        }
        OnlyofficeDTO onlyofficeDTO = new OnlyofficeDTO();
        onlyofficeDTO.setFileId(DigestUtil.md5Hex(file + file.getFileName()));
//        onlyofficeDTO.setFileUrl(fileUrl); 使用处自己填写
        onlyofficeDTO.setFileName(file.getFileName());
        onlyofficeDTO.setFilePath(file.getAllPath());
//        onlyofficeDTO.setType();使用处自己填写
        onlyofficeDTO.setExtendName(file.getExtName());
        onlyofficeDTO.setOfficeKey(file.getOfficeKey());
        onlyofficeDTO.setFileId(file.getId() + "");
        return onlyofficeDTO;
    }

    /**
     * 获取token
     *
     * @return
     */
    private String getTtoken() {
        return "1";
    }

    /***
     * 获取基础路径
     * @param request
     * @return
     */
    private String getBaseUrl(HttpServletRequest request) {
        if (StrUtil.isNotEmpty(apiHost)) {
            return apiHost;
        }
        return request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + request.getContextPath();
    }
}
